<?php
class TF_TreeBuilder // implements ITF_XmlParserCallback
{
 
    public $nodes=array();
    public $parent_uuid='';
    public $level_array=array(0);
    public $in_script=false;
    public $single_tag = array(
        'area',
        'base',
        'basefont',
        'br',
        'col',
        'frame',
        'hr',
        'img',
        'input',
		'isindex',
        'link',
        'meta',
        'param',
    );
    public function toText($uuid='')
    {
        //var_export($this->nodes);exit;
        if(!$uuid){
            $uuid='01234567-0123-0123-0123-012345678901';
        }
        $n=$this->nodes;
        if($n===false){
            //return $this->toText($this->tree);
            return false;
        }
        
        
        $i=0;
        $l=sizeof($n[$uuid]['$children']);
        $stack_cur=array($i);
        $stack_max=array($l);
        $ret='';
        
        $p=$this->nodes[$uuid];
        $cur_str='';
        while(true){
            if($l!=0 && isset($n['$tagname'])){
                $ret.=self::TagToText($n,$n['$tagname'],true,"\$","\$frag_");
                var_dump($ret);exit;
            }
            if($i!=$l){
                var_dump(__LINE__);var_dump($n);exit;
                $n=$p[$i];
                $l=isset($n['$children'])?sizeof($n['$children']):0;
                $p=$n;
                $i=0;
                array_push($stack_cur,$i);
                array_push($stack_max,$l);
             }else{
              var_dump(__LINE__);var_dump($ret);exit;
                $n=$p[$i];
                if(!empty($n['$data'])){
                    $ret.=$n['$data'];
                }else{
                    //$is_close=in_array($n['$tagname'],$this->single_tag);
                    //$ret.=self::TagToText($n,$n['$tagname'],true,"\$","\$frag_");
                }
                //$innertext="<div>".parent."</div>";
                array_pop($stack_cur);
                array_pop($stack_max);
                
                if(empty($stack_cur)){
                    break;
                }
                
                
                $stack_cur[sizeof($stack_cur)-1]++;
                $i=$stack_cur[sizeof($stack_cur)-1];
                
                $stack_max[sizeof($stack_cur)-1]++;
                $l=$stack_max[sizeof($stack_max)-1];
                $p=$p['parent'];
                //$cur_str=.'';
                continue;
            }
        }
        return $ret;
    }
    public function toText2($uuid='')
    {
        //var_export($this->nodes);exit;
        if(!$uuid){
            $uuid='01234567-0123-0123-0123-012345678901';
        }
        $n=$this->nodes[$uuid];
        
        
        if($n===false){
            return $this->toText($this->nodes);
        }
        $tagname='';
        $ret='';
        $type=$n['$type'];
        $is_close=false;
        
        if($type=='tag'){
            $tagname=$n['$tagname'];
            if($tagname){
                $is_close=in_array($tagname,$this->single_tag);
                $ret.=self::TagToText($n,$tagname,$is_close,"\$","\$frag_");
            }
        }
        
        if( isset($n['$children']) ){
            foreach($n['$children'] as $node_uuid){
                $ret.= $this->toText($node_uuid);
            }
            
        }
        if($tagname && !$is_close){
            $ret.='</'.$tagname.'>';
        }
        
        if(!empty($n['$data'])){
            $ret.=$n['$data'];
        }
        return $ret;
    }

    public function  __construct()
    {
        $uuid='01234567-0123-0123-0123-012345678901';
        $a=array(
            "\$uuid"=>$uuid,
            "\$parent"=>'',
            "\$type"=>"doc",
            "\$children"=>array(),
        );
        $this->nodes[$uuid]=$a;
        $this->parent_uuid=$uuid;
    }
    protected static function Uuid()  
    {
        $chars = md5(uniqid(mt_rand(), true));  
        $uuid  = substr($chars,0,8) . '-';  
        $uuid .= substr($chars,8,4) . '-';  
        $uuid .= substr($chars,12,4) . '-';  
        $uuid .= substr($chars,16,4) . '-';  
        $uuid .= substr($chars,20,12);  
        return $uuid;  
    }

    public function addTextChild($type,$str)
    {
        $uuid=self::Uuid();
        $a=array(
            "\$uuid"=>$uuid,
            "\$parent"=>$this->parent_uuid,
            "\$type" => $type,
            "\$data" => $str,
        );
        $this->nodes[$uuid]=$a;
        $p=&$this->nodes[$this->parent_uuid];
        $p["\$children"][]=$uuid;
    }

    public function tagbegin_handle($attrs)
    {
        $uuid=self::Uuid();
        $a=$attrs;
        
        $a["\$uuid"]=$uuid;
        $a["\$parent"]=$this->parent_uuid;
        $a["\$type"]="tag";
        $a["\$children"]=array();
        $this->nodes[$uuid]=$a;
        
        
        
        $p=&$this->nodes[$this->parent_uuid];
        $p["\$children"][]=$uuid;
        $this->parent_uuid=$uuid;
        
        if(strtolower($a["\$tagname"])=='script'){
            $this->in_script=true;
        }      
    }
    
    public function tagend_handle($tagname)
    {
        $this->in_script=false;
        $p=&$this->nodes[$this->parent_uuid];

        $this->parent_uuid=$p["\$parent"];
    }
     public function text_handle($text)
    {
        
    }
    
    public function error_handle( $array )
    {
        //
    }
    public function block_handle($type,$text)
    {
        if($type=='text'){
            if($this->in_script){
                $type='script';
            }
            $type=(''==trim($text))?'space':'text';
        }
       
        $this->addTextChild($type,$text);
    }
    // public function error_handle($error_code,$error_info);

    public static function TagToText($attrs,$tagname,$is_close,$ns_hidden="\n",$ns_frag="\nfrag_")
	{
		$ret='';
        $key_pre_frag_len=strlen($ns_frag);
        $ns_hidden_len=strlen($ns_hidden);
        
        $headdata=array();
        foreach( $attrs as $key => $value ){
            if( 0===strncmp($key,$ns_frag,$key_pre_frag_len) ){
                $headdata[]="$value";
                continue;
            }
            if( 0===strncmp($key,$ns_hidden,$ns_hidden_len) ){
                continue;
            }
            $headdata[]="$key=\"$value\"";
        }
        $ret="[$tagname".($headdata?' '.implode(' ',$headdata):'').(($is_close)?' /]':']');
        
		return $ret;
		
	}

    
}
